﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

namespace VSmityukh.WP.TitleLocalizationTool.Common
{
	internal class StringsTable
	{
		private readonly Dictionary<ushort, StringBlock> blocks;

		public StringsTable()
		{
			blocks = new Dictionary<ushort,StringBlock>();
		}

		public void Add(int stringID, string value)
		{
			StringBlock stringBlock;
			var blockID = GetBlockID(stringID);			
			
			if (!blocks.TryGetValue(blockID, out stringBlock))
			{
				stringBlock = new StringBlock(blockID);
				blocks.Add(blockID, stringBlock);
			}

			stringBlock[stringID] = value;
		}

		private ushort GetBlockID(int stringID)
		{
			return (ushort)(stringID / 16 + 1);
		}

		public StringBlock[] GetBlocks()
		{
			return blocks.Values.ToArray();
		}
	}

	internal class StringBlock
	{
		private readonly string[] strings;
		private readonly ushort blockID;
		private readonly int baseIndex;

		public StringBlock(ushort blockID)
		{
			this.blockID = blockID;
			
			strings = new string[16];
			baseIndex = (blockID - 1) * 16;
		}

		public ushort BlockID
		{
			get { return blockID; }
		}

		public string this[int stringID]
		{
			get
			{
				return strings[GetStringIndex(stringID)];
			}
			set
			{
				strings[GetStringIndex(stringID)] = value;
			}
		}

		public byte[] ToBytesArray()
		{
			using (var stream = new MemoryStream())
			using (var writer = new BinaryWriter(stream))
			{
				for (var index = 0; index < 16; index++)
				{
					var currentItem = strings[index];

					if (!string.IsNullOrEmpty(currentItem))
					{
						writer.Write((ushort)currentItem.Length);
						writer.Write(Encoding.Unicode.GetBytes(currentItem));
					}
					else
					{
						writer.Write((ushort)0);
					}
				}

				writer.Flush();
				return stream.ToArray();
			}
		}

		private int GetStringIndex(int stringID)
		{
			var result = stringID - baseIndex;

			if (result < 0 || result > 15)
			{
				var message = string.Format("String ID should be in range from {0} to {1}", baseIndex, baseIndex + 15);
				throw new ArgumentOutOfRangeException(message);
			}

			return result;
		}
	}
}
